home *** CD-ROM | disk | FTP | other *** search
/ STraTOS 1997 April & May / STraTOS 1 - 1997 April & May.iso / CD01 / GNU_KIT / DISK8.ZIP / src / makest / job.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-02-07  |  34.2 KB  |  1,495 lines

  1. /* Job execution and handling for GNU Make.
  2. Copyright (C) 1988-1991 Free Software Foundation, Inc.
  3. This file is part of GNU Make.
  4.  
  5. GNU Make is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 1, or (at your option)
  8. any later version.
  9.  
  10. GNU Make is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with GNU Make; see the file COPYING.  If not, write to
  17. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18.  
  19. #include "make.h"
  20. #include "commands.h"
  21. #include "job.h"
  22. #include "file.h"
  23. #include "variable.h"
  24. #include <errno.h>
  25.  
  26. /* Default path to search for executables.  */
  27. #ifdef atarist
  28. static char default_path[] = ":/bin:/usr/bin:/gnu/bin";
  29. #else
  30. static char default_path[] = ":/bin:/usr/bin";
  31. #endif
  32.  
  33. /* Default shell to use.  */
  34. char default_shell[] = "/bin/sh";
  35.  
  36. extern int errno;
  37.  
  38. #if    defined(USG) && !defined(HAVE_VFORK)
  39. #define    vfork    fork
  40. #define    VFORK_NAME    "fork"
  41. #else    /* Have vfork or not USG.  */
  42. #define    VFORK_NAME    "vfork"
  43. #endif    /* USG and don't have vfork.  */
  44. extern int vfork ();
  45.  
  46. #ifdef    _POSIX_SOURCE
  47. #include <sys/wait.h>
  48.  
  49. #define    WAIT_NOHANG(status)    waitpid(-1, (status), WNOHANG)
  50.  
  51. #else    /* Not _POSIX_SOURCE.  */
  52.  
  53. #if    defined(HAVE_SYS_WAIT) || !defined(USG)
  54. #include <sys/wait.h>
  55. #include <sys/time.h>
  56. #include <sys/resource.h>
  57.  
  58. #ifndef atarist
  59. #ifndef    wait3
  60. extern int wait3 ();
  61. #endif
  62. #define    WAIT_NOHANG(status)    wait3((status), WNOHANG, (struct rusage *) 0)
  63. #endif
  64.  
  65. #ifndef    wait
  66. extern int wait ();
  67. #endif
  68. #endif    /* HAVE_SYS_WAIT || !USG */
  69. #endif    /* _POSIX_SOURCE.  */
  70.  
  71. #if    defined(WTERMSIG) || (defined(USG) && !defined(HAVE_SYS_WAIT))
  72. #define    WAIT_T int
  73.  
  74. #ifndef    WTERMSIG
  75. #define WTERMSIG(x) ((x) & 0x7f)
  76. #endif
  77. #ifndef    WCOREDUMP
  78. #define WCOREDUMP(x) ((x) & 0x80)
  79. #endif
  80. #ifndef    WEXITSTATUS
  81. #define WEXITSTATUS(x) (((x) >> 8) & 0xff)
  82. #endif
  83. #ifndef    WIFSIGNALED
  84. #define WIFSIGNALED(x) (WTERMSIG (x) != 0)
  85. #endif
  86. #ifndef    WIFEXITED
  87. #define WIFEXITED(x) (WTERMSIG (x) == 0)
  88. #endif
  89.  
  90. #else    /* WTERMSIG not defined and have <sys/wait.h> or not USG.  */
  91.  
  92. #ifdef atarist
  93. #  define WAIT_T int
  94. #  define WTERMSIG(x) 0
  95. #  define WCOREDUMP(x) 0
  96. #  define WEXITSTATUS(x)  x
  97. #  define WIFSIGNALED(x) (WTERMSIG (x) != 0)
  98. #  define WIFEXITED(x) (WTERMSIG (x) == 0)
  99. #  undef WAIT_NOHANG
  100. #else
  101. #define WAIT_T union wait
  102. #define WTERMSIG(x)    ((x).w_termsig)
  103. #define WCOREDUMP(x)    ((x).w_coredump)
  104. #define WEXITSTATUS(x)    ((x).w_retcode)
  105. #endif /* atarist */
  106. #ifndef    WIFSIGNALED
  107. #define    WIFSIGNALED(x)    (WTERMSIG(x) != 0)
  108. #endif
  109. #ifndef    WIFEXITED
  110. #define    WIFEXITED(x)    (WTERMSIG(x) == 0)
  111. #endif
  112.  
  113. #endif    /* WTERMSIG defined or USG and don't have <sys/wait.h>.  */
  114.  
  115.  
  116. #if    defined(__GNU_LIBRARY__) || defined(_POSIX_SOURCE)
  117. #include <sys/types.h>
  118. #define    GID_T    gid_t
  119. #ifdef    hpux
  120. #include <sys/param.h>
  121. #define getdtablesize() NOFILE
  122. #endif
  123. #else    /* Not GNU C library.  */
  124.  
  125. #define    GID_T    int
  126.  
  127. extern int dup2 ();
  128. extern int fork (), execve ();
  129. extern void _exit ();
  130. extern int geteuid (), getegid ();
  131. extern int setgid (), getgid ();
  132.  
  133. #ifndef USG
  134. extern int getdtablesize ();
  135. #else
  136. #include <sys/param.h>
  137. #define getdtablesize() NOFILE
  138. #endif
  139. #endif    /* GNU C library.  */
  140.  
  141.  
  142. extern void wait_to_start_job ();
  143. extern int start_remote_job_p ();
  144. extern int start_remote_job (), remote_status ();
  145.  
  146.  
  147. #if    (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
  148. static char *sys_siglist[NSIG];
  149. void init_siglist ();
  150. #else    /* Not (USG and HAVE_SIGLIST), or DGUX.  */
  151. extern char *sys_siglist[];
  152. #endif    /* USG and not HAVE_SIGLIST, or DGUX.  */
  153.  
  154. int child_handler ();
  155. static void free_child (), start_job ();
  156.  
  157. /* Chain of all children.  */
  158.  
  159. struct child *children = 0;
  160.  
  161. /* Number of children currently running.  */
  162.  
  163. unsigned int job_slots_used = 0;
  164.  
  165. /* Nonzero if the `good' standard input is in use.  */
  166.  
  167. static int good_stdin_used = 0;
  168.  
  169. /* Write an error message describing the exit status given in
  170.    EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME.
  171.    Append "(ignored)" if IGNORED is nonzero.  */
  172.  
  173. static void
  174. child_error (target_name, exit_code, exit_sig, coredump, ignored)
  175.      char *target_name;
  176.      int exit_code, exit_sig, coredump;
  177.      int ignored;
  178. {
  179.   char *ignore_string = ignored ? " (ignored)" : "";
  180.  
  181.   if (exit_sig == 0)
  182.     error ("*** [%s] Error %d%s", target_name, exit_code, ignore_string);
  183.   else
  184.     {
  185.       char *coredump_string = coredump ? " (core dumped)" : "";
  186.       if (exit_sig > 0 && exit_sig < NSIG)
  187.     error ("*** [%s] %s%s",
  188.            target_name, sys_siglist[exit_sig], coredump_string);
  189.       else
  190.     error ("*** [%s] Signal %d%s", target_name, exit_sig, coredump_string);
  191.     }
  192. }
  193.  
  194. extern void block_remote_children (), unblock_remote_children ();
  195.  
  196. extern int fatal_signal_mask;
  197.  
  198. #ifdef    USG
  199. /* Set nonzero in the interval when it's possible that we may see a dead
  200.    child that's not in the `children' chain.  */
  201. static int unknown_children_possible = 0;
  202. #endif
  203.  
  204.  
  205. /* Block the child termination signal and fatal signals.  */
  206.  
  207. static void
  208. block_signals ()
  209. {
  210. #ifdef USG
  211.  
  212.   /* Tell child_handler that it might see children that aren't yet
  213.      in the `children' chain.  */
  214.   unknown_children_possible = 1;
  215.  
  216.   /* Ignoring SIGCLD makes wait always return -1.
  217.      Using the default action does the right thing.  */
  218.   (void) SIGNAL (SIGCLD, SIG_DFL);
  219.  
  220. #else    /* Not USG.  */
  221.  
  222.   /* Block the signals.  */
  223. #ifndef atarist
  224.   (void) sigblock (fatal_signal_mask | sigmask (SIGCHLD));
  225. #endif /* atarist */
  226.  
  227. #endif
  228.  
  229.   block_remote_children ();
  230. }
  231.  
  232. /* Unblock the child termination signal and fatal signals.  */
  233. static void
  234. unblock_signals ()
  235. {
  236. #ifdef    USG
  237.  
  238.   (void) SIGNAL (SIGCLD, child_handler);
  239.  
  240.   /* It should no longer be possible for children not in the chain to die.  */
  241.   unknown_children_possible = 0;
  242.  
  243. #else    /* Not USG.  */
  244.  
  245.   /* Unblock the signals.  */
  246. #ifndef atarist
  247.   (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask | sigmask (SIGCHLD)));
  248. #endif
  249.  
  250. #endif
  251.  
  252.   unblock_remote_children ();
  253. }
  254.  
  255. static char *signals_blocked_p_stack = 0;
  256. static unsigned int signals_blocked_p_max;
  257. static unsigned int signals_blocked_p_depth;
  258.  
  259. /* Make signals blocked in FLAG is nonzero, unblocked if FLAG is zero.
  260.    Push this setting on the signals_blocked_p_stack, so it can be
  261.    popped off by pop_signals_blocked_p.  */
  262.  
  263. void
  264. push_signals_blocked_p (flag)
  265.      int flag;
  266. {
  267.   int blocked;
  268.  
  269.   if (signals_blocked_p_stack == 0)
  270.     {
  271.       signals_blocked_p_max = 8;
  272.       signals_blocked_p_stack = (char *) xmalloc (8);
  273.       signals_blocked_p_depth = 1;
  274.       signals_blocked_p_stack[0] = flag;
  275.  
  276.       blocked = 0;
  277.     }
  278.   else
  279.     {
  280.       if (signals_blocked_p_depth == signals_blocked_p_max)
  281.     {
  282.       signals_blocked_p_max += 8;
  283.       signals_blocked_p_stack
  284.         = (char *) xrealloc(signals_blocked_p_stack,
  285.                 signals_blocked_p_max);
  286.     }
  287.  
  288.       blocked = (signals_blocked_p_depth > 0
  289.          && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
  290.  
  291.       signals_blocked_p_stack[++signals_blocked_p_depth - 1] = flag;
  292.     }
  293.  
  294.   if (blocked && !flag)
  295.     unblock_signals ();
  296.   else if (flag && !blocked)
  297.     block_signals ();
  298. }
  299.  
  300. /* Pop the signals_blocked_p setting from the stack
  301.    and block or unblock signals as appropriate.  */
  302.  
  303. void
  304. pop_signals_blocked_p ()
  305. {
  306.   int blocked, block;
  307.  
  308.   blocked = (signals_blocked_p_depth > 0
  309.          && signals_blocked_p_stack[signals_blocked_p_depth-- - 1]);
  310.  
  311.   block = (signals_blocked_p_depth > 0
  312.        && signals_blocked_p_stack[signals_blocked_p_depth - 1]);
  313.  
  314.   if (block && !blocked)
  315.     block_signals ();
  316.   else if (blocked && !block)
  317.     unblock_signals ();
  318. }
  319.  
  320. extern int shell_function_pid, shell_function_completed;
  321.  
  322. /* Handle a child-termination signal (SIGCHLD, or SIGCLD for USG),
  323.    storing the returned status and the new command state (`cs_finished')
  324.    in the `file' member of the `struct child' for the dead child,
  325.    and removing the child from the chain.
  326.  
  327.    If we were called as a signal handler, SIG should be SIGCHLD
  328.    (SIGCLD for USG).  If instead it is zero, we were called explicitly
  329.    and should block waiting for running children.
  330.    If SIG is < 0, - SIG is the maximum number of children to bury (record
  331.    status of and remove from the chain).  */
  332.  
  333. int
  334. child_handler (sig)
  335.      int sig;
  336. {
  337.   WAIT_T status;
  338.   unsigned int dead_children = 0;
  339.  
  340.   if (sig > 0)
  341.     block_signals ();
  342.  
  343.   while (1)
  344.     {
  345.       int remote = 0;
  346.       register int pid;
  347.       int exit_code, exit_sig, coredump;
  348.       register struct child *lastc, *c;
  349.       int child_failed;
  350.  
  351.       /* First, check for remote children.  */
  352.       pid = remote_status (&exit_code, &exit_sig, &coredump, 0);
  353.       if (pid < 0)
  354.     {
  355.       /* No remote children.  Check for local children.  */
  356.  
  357. #ifdef    WAIT_NOHANG
  358.       if (sig > 0)
  359.         pid = WAIT_NOHANG (&status);
  360.       else
  361.         pid = wait (&status);
  362. #else    /* USG and don't HAVE_SYS_WAIT.  */
  363.       /* System V cannot do non-blocking waits, so we have two
  364.          choices if called as a signal handler: handle only one
  365.          child (there may be more if the signal was blocked),
  366.          or block waiting for more.  The latter option makes
  367.          parallelism useless, so we must choose the former.  */
  368.       pid = wait (&status);
  369. #endif    /* HAVE_SYS_WAIT or not USG.  */
  370.  
  371.       if (pid <= 0)
  372.         /* No local children.  */
  373.         break;
  374.       else
  375.         {
  376.           /* Chop the status word up.  */
  377.           exit_code = WEXITSTATUS (status);
  378.           exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0;
  379.           coredump = WCOREDUMP (status);
  380.         }
  381.     }
  382.       else
  383.     /* We got a remote child.  */
  384.     remote = 1;
  385.  
  386.       /* Check if this is the child of the `shell' function.  */
  387.       if (!remote && pid == shell_function_pid)
  388.     {
  389.       /* It is.  Leave an indicator for the `shell' function.  */
  390.       if (exit_sig == 0 && exit_code == 127)
  391.         shell_function_completed = -1;
  392.       else
  393.         shell_function_completed = 1;
  394.  
  395.       /* Check if we have reached our quota of children.  */
  396.       ++dead_children;
  397.       if (sig < 0 && dead_children == -sig)
  398.         break;
  399. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  400.       else if (sig > 0)
  401.         break;
  402. #endif
  403.       else
  404.         continue;
  405.     }
  406.  
  407.       child_failed = exit_sig != 0 || exit_code != 0;
  408.  
  409.       /* Search for a child matching the deceased one.  */
  410.       lastc = 0;
  411.       for (c = children; c != 0; lastc = c, c = c->next)
  412.     if (c->remote == remote && c->pid == pid)
  413.       break;
  414.  
  415.       if (c == 0)
  416.     {
  417.       /* An unknown child died.  */
  418. #ifdef    USG
  419.       if (!unknown_children_possible)
  420.         {
  421. #endif
  422.           char buf[100];
  423.           sprintf (buf, "Unknown%s job %d", remote ? " remote" : "", pid);
  424.           if (child_failed)
  425.         child_error (buf, exit_code, exit_sig, coredump,
  426.                  ignore_errors_flag);
  427.           else
  428.         error ("%s finished.", buf);
  429. #ifdef    USG
  430.         }
  431. #endif
  432.     }
  433.       else
  434.     {
  435.       /* If this child had the good stdin, say it is now free.  */
  436.       if (c->good_stdin)
  437.         good_stdin_used = 0;
  438.  
  439.       if (child_failed && !c->noerror && !ignore_errors_flag)
  440.         {
  441.           /* The commands failed.  Write an error message,
  442.          delete non-precious targets, and abort.  */
  443.           child_error (c->file->name, exit_code, exit_sig, coredump, 0);
  444.           c->file->update_status = 1;
  445.           if (exit_sig != 0)
  446.         delete_child_targets (c);
  447.         }
  448.       else
  449.         {
  450.           if (child_failed)
  451.         {
  452.           /* The commands failed, but we don't care.  */
  453.           child_error (c->file->name,
  454.                    exit_code, exit_sig, coredump, 1);
  455.           child_failed = 0;
  456.         }
  457.  
  458.           /* If there are more commands to run, try to start them.  */
  459.           start_job (c);
  460.  
  461.           switch (c->file->command_state)
  462.         {
  463.         case cs_running:
  464.           /* Successfully started.  Loop to reap more children.  */
  465.           continue;
  466.  
  467.         case cs_finished:
  468.           if (c->file->update_status != 0)
  469.             {
  470.               /* We failed to start the commands.  */
  471.               delete_child_targets (c);
  472.             }
  473.           break;
  474.  
  475.         default:
  476.           error ("internal error: `%s' command_state \
  477. %d in child_handler", c->file->name);
  478.           abort ();
  479.           break;
  480.         }
  481.         }
  482.  
  483.       /* Set the state flag to say the commands have finished.  */
  484.       c->file->command_state = cs_finished;
  485.       notice_finished_file (c->file);
  486.  
  487.       /* Remove the child from the chain and free it.  */
  488.       if (lastc == 0)
  489.         children = c->next;
  490.       else
  491.         lastc->next = c->next;
  492.       free_child (c);
  493.  
  494.       /* There is now another slot open.  */
  495.       --job_slots_used;
  496.  
  497.       /* If the job failed, and the -k flag was not given, die.  */
  498.       if (child_failed && !keep_going_flag)
  499.         die (1);
  500.  
  501.       /* See if we have reached our quota for blocking.  */
  502.       ++dead_children;
  503.       if (sig < 0 && dead_children == -sig)
  504.         break;
  505. #if    defined(USG) && !defined(HAVE_SYS_WAIT)
  506.       else if (sig > 0)
  507.         break;
  508. #endif
  509.     }
  510.     }
  511.  
  512. #ifdef    USG
  513.   if (sig > 0)
  514.     (void) SIGNAL (sig, child_handler);
  515. #endif
  516.  
  517.   if (sig > 0)
  518.     unblock_signals ();
  519.  
  520.   return 0;
  521. }
  522.  
  523.  
  524. /* Wait for N children, blocking if necessary.
  525.    If N is zero, wait until we run out of children.
  526.    If ERR is nonzero and we have any children to wait for,
  527.    print a message on stderr.  */
  528.  
  529. void
  530. wait_for_children (n, err)
  531.      unsigned int n;
  532.      int err;
  533. {
  534.   push_signals_blocked_p (1);
  535.  
  536.   if (err && (children != 0 || shell_function_pid != 0))
  537.     {
  538.       fflush (stdout);
  539.       error ("*** Waiting for unfinished jobs....");
  540.     }
  541.  
  542.   /* Call child_handler to do the work.  */
  543.   (void) child_handler (- (int) n);
  544.  
  545.   pop_signals_blocked_p ();
  546. }
  547.  
  548. /* Free the storage allocated for CHILD.  */
  549.  
  550. static void
  551. free_child (child)
  552.      register struct child *child;
  553. {
  554.   if (child->command_lines != 0)
  555.     {
  556.       register unsigned int i;
  557.       for (i = 0; i < child->file->cmds->ncommand_lines; ++i)
  558.     free (child->command_lines[i]);
  559.       free ((char *) child->command_lines);
  560.     }
  561.  
  562.   if (child->environment != 0)
  563.     {
  564.       register char **ep = child->environment;
  565.       while (*ep != 0)
  566.     free (*ep++);
  567.       free ((char *) child->environment);
  568.     }
  569.  
  570.   free ((char *) child);
  571. }
  572.  
  573. /* Start a job to run the commands specified in CHILD.
  574.    CHILD is updated to reflect the commands and ID of the child process.  */
  575.  
  576. static void
  577. start_job (child)
  578.      register struct child *child;
  579. {
  580.   static int bad_stdin = -1;
  581.   char *end;
  582.   register char *p;
  583.   int backslash;
  584.   char noprint = 0, recursive;
  585.   char **argv;
  586.  
  587.   /* Set RECURSIVE if the unexpanded line contains $(MAKE).  */
  588.   recursive = child->file->cmds->lines_recurse[child->command_line];
  589.  
  590.   if (child->command_ptr == 0 || *child->command_ptr == '\0')
  591.     {
  592.       /* There are no more lines in the expansion of this line.  */
  593.       if (child->command_line == child->file->cmds->ncommand_lines)
  594.     {
  595.       /* There are no more lines to be expanded.  */
  596.       child->command_ptr = 0;
  597.       child->file->command_state = cs_finished;
  598.       child->file->update_status = 0;
  599.       return;
  600.     }
  601.       else
  602.     /* Get the next line to run.  */
  603.     child->command_ptr = child->command_lines[child->command_line++];
  604.     }
  605.  
  606.   /* Find the end of this line.  Backslash-newlines don't mean the end.  */
  607.  
  608.   end = child->command_ptr;
  609.   while (*end != '\0')
  610.     {
  611.       p = index (end, '\n');
  612.       if (p == 0)
  613.     {
  614.       end += strlen (end);
  615.       break;
  616.     }
  617.  
  618.       end = p;
  619.       backslash = 0;
  620.       while (*--p == '\\')
  621.     backslash = !backslash;
  622.  
  623.       if (backslash)
  624.     {
  625.       ++end;
  626.       /* If there is a tab after a backslash-newline,
  627.          remove it, since it was most likely used to line
  628.          up the continued line with the previous one.  */
  629.       if (*end == '\t')
  630.         strcpy (end, end + 1);
  631.     }
  632.       else
  633.     break;
  634.     }
  635.  
  636.   p = child->command_ptr;
  637.  
  638.   if (*end == '\0')
  639.     child->command_ptr = 0;
  640.   else
  641.     {
  642.       *end = '\0';
  643.       child->command_ptr = end + 1;
  644.     }
  645.  
  646.   child->noerror = 0;
  647.   while (*p != '\0')
  648.     {
  649.       if (*p == '@')
  650.     noprint = 1;
  651.       else if (*p == '-')
  652.     child->noerror = 1;
  653.       else if (*p == '+')
  654.     recursive = 1;
  655.       else if (*p != ' ' && *p != '\t')
  656.     break;
  657.       ++p;
  658.     }
  659.  
  660.   /* If -q was given, just say that updating `failed'.  */
  661.   if (question_flag && !recursive)
  662.     goto error;
  663.  
  664.   /* There may be some preceding whitespace left if there
  665.      was nothing but a backslash on the first line.  */
  666.   p = next_token (p);
  667.  
  668.   if (*p == '\0')
  669.     {
  670.       /* There were no commands on this line.  Go to the next.  */
  671.       start_job (child);
  672.       return;
  673.     }
  674.  
  675.   /* Print out the command.  */
  676.  
  677.   if (just_print_flag || (!noprint && !silent_flag))
  678.     puts (p);
  679.  
  680.   /* If -n was given, recurse to get the next line in the sequence.  */
  681.  
  682.   if (just_print_flag && !recursive)
  683.     {
  684.       start_job (child);
  685.       return;
  686.     }
  687.  
  688.   /* Collapse backslash-newlines in this line.  */
  689.  
  690.   collapse_continuations (p);
  691.  
  692.   /* Figure out an argument list from this command line.  */
  693.  
  694.   argv = construct_command_argv (p, child->file);
  695.  
  696.   if (argv == 0)
  697.     {
  698.       /* This line has no commands.  Go to the next.  */
  699.       start_job (child);
  700.       return;
  701.     }
  702.  
  703.   /* Flush the output streams so they won't have things written twice.  */
  704.  
  705.   fflush (stdout);
  706.   fflush (stderr);
  707.   
  708.   /* Set up a bad standard input that reads from a broken pipe.  */
  709.  
  710. #ifndef atarist
  711.   if (bad_stdin == -1)
  712.     {
  713.       /* Make a file descriptor that is the read end of a broken pipe.
  714.      This will be used for some children's standard inputs.  */
  715.       int pd[2];
  716.       if (pipe (pd) == 0)
  717.     {
  718.       /* Close the write side.  */
  719.       (void) close (pd[1]);
  720.       /* Save the read side.  */
  721.       bad_stdin = pd[0];
  722.     }
  723.     }
  724. #endif
  725.  
  726.   /* Decide whether to give this child the `good' standard input
  727.      (one that points to the terminal or whatever), or the `bad' one
  728.      that points to the read side of a broken pipe.  */
  729.  
  730.   child->good_stdin = !good_stdin_used;
  731.   if (child->good_stdin)
  732.     good_stdin_used = 1;
  733.  
  734.   child->deleted = 0;
  735.  
  736.   /* Set up the environment for the child.  */
  737.   if (child->environment == 0)
  738.     child->environment = target_environment (child->file);
  739.  
  740.   if (start_remote_job_p ())
  741.     {
  742.       int is_remote, id, used_stdin;
  743.       if (start_remote_job (argv, child->good_stdin ? 0 : bad_stdin,
  744.                 &is_remote, &id, &used_stdin))
  745.     goto error;
  746.       else
  747.     {
  748.       if (child->good_stdin && !used_stdin)
  749.         {
  750.           child->good_stdin = 0;
  751.           good_stdin_used = 0;
  752.         }
  753.       child->remote = is_remote;
  754.       child->pid = id;
  755.     }
  756.     }
  757.   else
  758.     {
  759.       if (child->command_line - 1 == 0)
  760.     {
  761.       /* Wait for the load to be low enough if this
  762.          is the first command in the sequence.  */
  763.       make_access ();
  764.       wait_to_start_job ();
  765.       user_access ();
  766.     }
  767.  
  768.       /* Fork the child process.  */
  769.  
  770.       child->remote = 0;
  771.       child->pid = vfork ();
  772.       if (child->pid == 0)
  773.     /* We are the child side.  */
  774.     child_execute_job (child->good_stdin ? 0 : bad_stdin, 1,
  775.                argv, child->environment);
  776.       else if (child->pid < 0)
  777.     {
  778.       /* Fork failed!  */
  779.       perror_with_name (VFORK_NAME, "");
  780.       goto error;
  781.     }
  782.     }
  783.  
  784.   /* We are the parent side.  Set the state to
  785.      say the commands are running and return.  */
  786.  
  787.   child->file->command_state = cs_running;
  788.  
  789.   /* Free the storage used by the child's argument list.  */
  790.  
  791.   free (argv[0]);
  792.   free ((char *) argv);
  793.  
  794.   return;
  795.  
  796.  error:;
  797.   child->file->update_status = 1;
  798.   child->file->command_state = cs_finished;
  799. }
  800.  
  801.  
  802. /* Create a `struct child' for FILE and start its commands running.  */
  803.  
  804. void
  805. new_job (file)
  806.      register struct file *file;
  807. {
  808.   register struct commands *cmds = file->cmds;
  809.   register struct child *c;
  810.   char **lines;
  811.   register unsigned int i;
  812.  
  813.   /* Chop the commands up into lines if they aren't already.  */
  814.   chop_commands (cmds);
  815.  
  816.   if (job_slots > 0)
  817.     /* Wait for a job slot to be freed up.  */
  818.     while (job_slots_used == job_slots)
  819.       wait_for_children (1, 0);
  820.  
  821.   /* Expand the command lines and store the results in LINES.  */
  822.   lines = (char **) xmalloc (cmds->ncommand_lines * sizeof (char *));
  823.   for (i = 0; i < cmds->ncommand_lines; ++i)
  824.     lines[i] = allocated_variable_expand_for_file (cmds->command_lines[i],
  825.                            file);
  826.  
  827.   /* Start the command sequence, record it in a new
  828.      `struct child', and add that to the chain.  */
  829.  
  830.   push_signals_blocked_p (1);
  831.  
  832.   c = (struct child *) xmalloc (sizeof (struct child));
  833.   c->file = file;
  834.   c->command_lines = lines;
  835.   c->command_line = 0;
  836.   c->command_ptr = 0;
  837.   c->environment = 0;
  838.   start_job (c);
  839.   switch (file->command_state)
  840.     {
  841.     case cs_running:
  842.       c->next = children;
  843.       children = c;
  844.       /* One more job slot is in use.  */
  845.       ++job_slots_used;
  846.       break;
  847.  
  848.     case cs_finished:
  849.       free_child (c);
  850.       notice_finished_file (file);
  851.       break;
  852.  
  853.     default:
  854.       error ("internal error: `%s' command_state == %d in new_job",
  855.          file->name, (int) file->command_state);
  856.       abort ();
  857.       break;
  858.     }
  859.  
  860.   pop_signals_blocked_p ();
  861.  
  862.   if (job_slots == 1 && file->command_state == cs_running)
  863.     {
  864.       /* Since there is only one job slot, make things run linearly.
  865.      Wait for the child to finish, setting the state to `cs_finished'.  */
  866.       while (file->command_state != cs_finished)
  867.     wait_for_children (1, 0);
  868.     }
  869. }
  870.  
  871. /* Replace the current process with one executing the command in ARGV.
  872.    STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is
  873.    the environment of the new program.  This function does not return.  */
  874.  
  875. void
  876. child_execute_job (stdin_fd, stdout_fd, argv, envp)
  877.      int stdin_fd, stdout_fd;
  878.      char **argv, **envp;
  879. {
  880.   if (stdin_fd != 0)
  881.     (void) dup2 (stdin_fd, 0);
  882.   if (stdout_fd != 1)
  883.     (void) dup2 (stdout_fd, 1);
  884.  
  885. #ifndef atarist
  886.   /* Free up file descriptors.  */
  887.   {
  888.     register int d;
  889.     int max = getdtablesize ();
  890.     for (d = 3; d < max; ++d)
  891.       (void) close (d);
  892.   }
  893. #endif /* atarist */
  894.  
  895.   /* Don't block signals for the new process.  */
  896.   unblock_signals ();
  897.  
  898.   /* Run the command.  */
  899.   exec_command (argv, envp);
  900. }
  901.  
  902. /* Search PATH for FILE.
  903.    If successful, store the full pathname in PROGRAM and return 1.
  904.    If not sucessful, return zero.  */
  905.  
  906. static int
  907. search_path (file, path, program)
  908.      char *file, *path, *program;
  909. {
  910.   if (path == 0 || path[0] == '\0')
  911.     path = default_path;
  912.  
  913.   if (index (file, '/') != 0)
  914.     {
  915.       strcpy (program, file);
  916.       return 1;
  917.     }
  918.   else
  919. #ifdef atarist
  920.   {
  921.       static char  * * _extensions = 0,  * suff;
  922.       char         * p,  * q;
  923.       int            i;
  924.       
  925.       if ( _extensions == 0 )
  926.       {
  927.       if ( ( p == (char*)getenv( "SUFF" ) ) != 0 && *p )
  928.       {
  929.           suff = (char*) xmalloc( strlen( p ) + 1 );
  930.           strcpy( suff, p );
  931.           for ( i = 1, q = suff;  *q;  q++ )
  932.           if ( *q == ',' || *q == ';' )
  933.               i++;
  934.           _extensions = (char**) xmalloc( i * sizeof( char* ) );
  935.           _extensions[0] = suff;
  936.           for ( i = 0, q = suff;  *q;  q++ )
  937.           if ( *q == ',' || *q == ';' )
  938.           {
  939.               *q = '\0';
  940.               _extensions[ ++i ] = q + 1;
  941.           }
  942.           _extensions[ ++i ] = 0;
  943.       }
  944.           else
  945.           {
  946.           _extensions = (char**) xmalloc( 5 * sizeof( char* ) );
  947.           _extensions[0] = "ttp";
  948.           _extensions[1] = "tos";
  949.           _extensions[2] = "prg";
  950.           _extensions[3] = "app";
  951.           _extensions[4] = 0;
  952.       }
  953.       }
  954.       p = (char*) findfile( file, path, _extensions );
  955.       if ( p == NULL )
  956.       return 0;
  957.       else
  958.       {
  959.       strcpy( program, p );
  960.       return 1;
  961.       }
  962.   }
  963. #else
  964.     {
  965.       unsigned int len;
  966.  
  967. #ifndef    USG
  968.       extern int getgroups ();
  969.       static GID_T groups[NGROUPS];
  970.       static int ngroups = -1;
  971.       if (ngroups == -1)
  972.     ngroups = getgroups (NGROUPS, groups);
  973. #endif    /* Not USG.  */
  974.  
  975.       len = strlen (file) + 1;
  976.       do
  977.     {
  978.       struct stat st;
  979.       int perm;
  980.       char *p;
  981.  
  982.       p = index (path, ':');
  983.       if (p == 0)
  984.         p = path + strlen (path);
  985.  
  986.       if (p == path)
  987.         bcopy (file, program, len);
  988.       else
  989.         {
  990.           bcopy (path, program, p - path);
  991.           program[p - path] = '/';
  992.           bcopy (file, program + (p - path) + 1, len);
  993.         }
  994.  
  995.       if (stat (program, &st) == 0
  996.           && S_ISREG (st.st_mode))
  997.         {
  998.           if (st.st_uid == geteuid ())
  999.         perm = (st.st_mode & 0100);
  1000.           else if (st.st_gid == getegid ())
  1001.         perm = (st.st_mode & 0010);
  1002.           else
  1003.         {
  1004. #ifndef    USG
  1005.           register int i;
  1006.           for (i = 0; i < ngroups; ++i)
  1007.             if (groups[i] == st.st_gid)
  1008.               break;
  1009.           if (i < ngroups)
  1010.             perm = (st.st_mode & 0010);
  1011.           else
  1012. #endif    /* Not USG.  */
  1013.             perm = (st.st_mode & 0001);
  1014.         }
  1015.  
  1016.           if (perm != 0)
  1017.         return 1;
  1018.         }
  1019.  
  1020.       path = p + 1;
  1021.     } while (*path != '\0');
  1022.     }
  1023.  
  1024.   return 0;
  1025. #endif /* atarist */
  1026. }
  1027.  
  1028. /* Replace the current process with one running the command in ARGV,
  1029.    with environment ENVP.  This function does not return.  */
  1030.  
  1031. void
  1032. exec_command (argv, envp)
  1033.      char **argv, **envp;
  1034. {
  1035.   char *shell, *path;
  1036.   char program[MAXPATHLEN];
  1037.   register char **ep;
  1038.  
  1039.   shell = path = 0;
  1040.   for (ep = envp; *ep != 0; ++ep)
  1041.     {
  1042.       if (shell == 0 && !strncmp(*ep, "SHELL=", 6))
  1043.     shell = &(*ep)[6];
  1044.       else if (path == 0 && !strncmp(*ep, "PATH=", 5))
  1045.     path = &(*ep)[5];
  1046.       else if (path != 0 && shell != 0)
  1047.     break;
  1048.     }
  1049.  
  1050.   /* Be the user.  */
  1051.   user_access ();
  1052.  
  1053.   if (!search_path (argv[0], path, program))
  1054.     error ("%s: Command not found", argv[0]);
  1055.   else
  1056.     {
  1057.       /* Run the program.  */
  1058.  
  1059.       execvp (program, argv);
  1060.  
  1061.       if (errno == ENOEXEC)
  1062.     {
  1063.       char shell_program[MAXPATHLEN], *shell_path;
  1064.       if (shell == 0)
  1065.         shell_path = default_shell;
  1066.       else
  1067.         {
  1068.           if (search_path (shell, path, shell_program))
  1069.         shell_path = shell_program;
  1070.           else
  1071.         {
  1072.           shell_path = 0;
  1073.           error ("%s: Shell program not found", shell);
  1074.         }
  1075.         }
  1076.  
  1077.       if (shell_path != 0)
  1078.         {
  1079.           char **new_argv;
  1080.           int argc;
  1081.  
  1082.           argc = 1;
  1083.           while (argv[argc] != 0)
  1084.         ++argc;
  1085.  
  1086.           new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *));
  1087.           new_argv[0] = shell_path;
  1088.           new_argv[1] = program;
  1089.           while (argc > 0)
  1090.         {
  1091.           new_argv[1 + argc] = argv[argc];
  1092.           --argc;
  1093.         }
  1094.           execvp (shell_path, new_argv, envp);
  1095.           perror_with_name ("execvp: ", shell_path);
  1096.         }
  1097.     }
  1098.       else
  1099.     perror_with_name ("execvp: ", program);
  1100.     }
  1101.  
  1102.   _exit (127);
  1103. }
  1104.  
  1105. /* Figure out the argument list necessary to run LINE as a command.
  1106.    Try to avoid using a shell.  This routine handles only ' quoting.
  1107.    Starting quotes may be escaped with a backslash.  If any of the
  1108.    characters in sh_chars[] is seen, or any of the builtin commands
  1109.    listed in sh_cmds[] is the first word of a line, the shell is used.
  1110.  
  1111.    SHELL is the shell to use, or nil to use the default shell.
  1112.    IFS is the value of $IFS, or nil (meaning the default).  */
  1113.  
  1114. static char **
  1115. construct_command_argv_internal (line, shell, ifs)
  1116.      char *line;
  1117.      char *shell, *ifs;
  1118. {
  1119.   static char sh_chars[] = "#;\"*?[]&|<>(){}=$`";
  1120.   static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login",
  1121.                  "logout", "set", "umask", "wait", "while", "for",
  1122.                  "case", "if", ":", ".", "break", "continue",
  1123.                  "export", "read", "readonly", "shift", "times",
  1124.                  "trap", "switch", 0 };
  1125.   register int i;
  1126.   register char *p;
  1127.   register char *ap;
  1128.   char *end;
  1129.   int instring;
  1130.   char **new_argv = 0;
  1131.  
  1132.   /* See if it is safe to parse commands internally.  */
  1133.   if (shell != 0 && strcmp (shell, default_shell))
  1134.     goto slow;
  1135.  
  1136.   if (ifs != 0)
  1137.     for (ap = ifs; *ap != '\0'; ++ap)
  1138.       if (*ap != ' ' && *ap != '\t' && *ap != '\n')
  1139.     goto slow;
  1140.  
  1141.   i = strlen (line) + 1;
  1142.  
  1143.   /* More than 1 arg per character is impossible.  */
  1144.   new_argv = (char **) xmalloc (i * sizeof (char *));
  1145.  
  1146.   /* All the args can fit in a buffer as big as LINE is.   */
  1147.   ap = new_argv[0] = (char *) xmalloc (i);
  1148.   end = ap + i;
  1149.  
  1150.   /* I is how many complete arguments have been found.  */
  1151.   i = 0;
  1152.   instring = 0;
  1153.   for (p = line; *p != '\0'; ++p)
  1154.     {
  1155.       if (ap > end)
  1156.     abort ();
  1157.  
  1158.       if (instring)
  1159.     {
  1160.       /* Inside a string, just copy any char except a closing quote.  */
  1161.       if (*p == '\'')
  1162.         instring = 0;
  1163.       else
  1164.         *ap++ = *p;
  1165.     }
  1166.       else if (index (sh_chars, *p) != 0)
  1167.     /* Not inside a string, but it's a special char.  */
  1168.     goto slow;
  1169.       else
  1170.     /* Not a special char.  */
  1171.     switch (*p)
  1172.       {
  1173. #ifdef atarist
  1174.       case '@':
  1175. #else
  1176.       case '\\':
  1177. #endif
  1178.         if (p[1] != '\0' && p[1] != '\n')
  1179.           /* Copy and skip the following char.  */
  1180.           *ap++ = *++p;
  1181.         break;
  1182.  
  1183.       case '\'':
  1184.         instring = 1;
  1185.         break;
  1186.  
  1187.       case '\n':
  1188.       case ' ':
  1189.       case '\t':
  1190.         /* We have the end of an argument.
  1191.            Terminate the text of the argument.  */
  1192.         *ap++ = '\0';
  1193.         new_argv[++i] = ap;
  1194.         /* If this argument is the command name,
  1195.            see if it is a built-in shell command.
  1196.            If so, have the shell handle it.  */
  1197.         if (i == 1)
  1198.           {
  1199.         register int j;
  1200.         for (j = 0; sh_cmds[j] != 0; ++j)
  1201.           if (streq (sh_cmds[j], new_argv[0]))
  1202.             goto slow;
  1203.           }
  1204.  
  1205.         /* Ignore multiple whitespace chars.  */
  1206.         p = next_token (p);
  1207.         /* Next iteration should examine the first nonwhite char.  */
  1208.         --p;
  1209.         break;
  1210.  
  1211.       default:
  1212.         *ap++ = *p;
  1213.         break;
  1214.       }
  1215.     }
  1216.  
  1217.   if (instring)
  1218.     /* Let the shell deal with an unterminated quote.  */
  1219.     goto slow;
  1220.  
  1221.   /* Terminate the last argument and the argument list.  */
  1222.  
  1223.   *ap = '\0';
  1224.   if (new_argv[i][0] != '\0')
  1225.     ++i;
  1226.   new_argv[i] = 0;
  1227.  
  1228.   if (new_argv[0] == 0)
  1229.     /* Line was empty.  */
  1230.     return 0;
  1231.   else
  1232.     return new_argv;
  1233.  
  1234.  slow:;
  1235.   /* We must use the shell.  */
  1236.  
  1237.   if (new_argv != 0)
  1238.     {
  1239.       /* Free the old argument list we were working on.  */
  1240.       free (new_argv[0]);
  1241.       free (new_argv);
  1242.     }
  1243.  
  1244.   if (shell == 0 || !strcmp (shell, default_shell))
  1245.     {
  1246.       /* The shell is the default, or we're in a recursive call to construct
  1247.      the argument list for the real shell.  Construct a simple argument
  1248.      list using the default shell.  */
  1249.       new_argv = (char **) xmalloc (4 * sizeof (char *));
  1250.       new_argv[0] = savestring (default_shell, sizeof (default_shell) - 1);
  1251.       new_argv[1] = "-c";
  1252.       new_argv[2] = savestring (line, strlen (line));
  1253.       new_argv[3] = 0;
  1254.     }
  1255.   else
  1256.     {
  1257.       /* SHELL may be a multi-word command.  Construct a command line
  1258.      "SHELL -c LINE", with all special chars in LINE escaped.
  1259.      Then recurse, expanding this command line to get the final
  1260.      argument list.  */
  1261.  
  1262.       unsigned int shell_len = strlen (shell);
  1263.       static char minus_c[] = " -c ";
  1264.       unsigned int line_len = strlen (line);
  1265.       
  1266.       char *new_line = (char *) alloca (shell_len + (sizeof (minus_c) - 1)
  1267.                     + (line_len * 2) + 1);
  1268.  
  1269.       ap = new_line;
  1270.       bcopy (shell, ap, shell_len);
  1271.       ap += shell_len;
  1272.       bcopy (minus_c, ap, sizeof (minus_c) - 1);
  1273.       ap += sizeof (minus_c) - 1;
  1274.       for (p = line; *p != '\0'; ++p)
  1275.     {
  1276.       if (*p == '\\' || *p == '\''
  1277.           || *p == ' ' || *p == '\t' || *p == '\n'
  1278.           || index (sh_chars, *p) != 0)
  1279. #ifdef atarist
  1280.         *ap++ = '@';
  1281. #else
  1282.         *ap++ = '\\';
  1283. #endif
  1284.       *ap++ = *p;
  1285.     }
  1286.       *ap = '\0';
  1287.  
  1288.       new_argv = construct_command_argv_internal (new_line,
  1289.                           (char *) 0, (char *) 0);
  1290.     }
  1291.  
  1292.   return new_argv;
  1293. }
  1294.  
  1295. /* Figure out the argument list necessary to run LINE as a command.
  1296.    Try to avoid using a shell.  This routine handles only ' quoting.
  1297.    Starting quotes may be escaped with a backslash.  If any of the
  1298.    characters in sh_chars[] is seen, or any of the builtin commands
  1299.    listed in sh_cmds[] is the first word of a line, the shell is used.
  1300.  
  1301.    FILE is the target whose commands these are.  It is used for
  1302.    variable expansion for $(SHELL) and $(IFS).  */
  1303.  
  1304. char **
  1305. construct_command_argv (line, file)
  1306.      char *line;
  1307.      struct file *file;
  1308. {
  1309.   char *shell = allocated_variable_expand_for_file ("$(SHELL)", file);
  1310.   char *ifs = allocated_variable_expand_for_file ("$(IFS)", file);
  1311.   char **argv;
  1312.  
  1313.   argv = construct_command_argv_internal (line, shell, ifs);
  1314.  
  1315.   free (shell);
  1316.   free (ifs);
  1317.  
  1318.   return argv;
  1319. }
  1320.  
  1321. #if    (defined(USG) && !defined(HAVE_SIGLIST)) || defined(DGUX)
  1322. /* Initialize sys_siglist.  */
  1323.  
  1324. void
  1325. init_siglist ()
  1326. {
  1327.   char buf[100];
  1328.   register unsigned int i;
  1329.  
  1330.   for (i = 0; i < NSIG; ++i)
  1331.     switch (i)
  1332.       {
  1333.       default:
  1334.     sprintf (buf, "Signal %u", i);
  1335.     sys_siglist[i] = savestring (buf, strlen (buf));
  1336.     break;
  1337.       case SIGHUP:
  1338.     sys_siglist[i] = "Hangup";
  1339.     break;
  1340.       case SIGINT:
  1341.     sys_siglist[i] = "Interrupt";
  1342.     break;
  1343.       case SIGQUIT:
  1344.     sys_siglist[i] = "Quit";
  1345.     break;
  1346.       case SIGILL:
  1347.     sys_siglist[i] = "Illegal Instruction";
  1348.     break;
  1349.       case SIGTRAP:
  1350.     sys_siglist[i] = "Trace Trap";
  1351.     break;
  1352.       case SIGIOT:
  1353.     sys_siglist[i] = "IOT Trap";
  1354.     break;
  1355. #ifdef    SIGEMT
  1356.       case SIGEMT:
  1357.     sys_siglist[i] = "EMT Trap";
  1358.     break;
  1359. #endif
  1360. #ifdef    SIGDANGER
  1361.       case SIGDANGER:
  1362.     sys_siglist[i] = "Danger signal";
  1363.     break;
  1364. #endif
  1365.       case SIGFPE:
  1366.     sys_siglist[i] = "Floating Point Exception";
  1367.     break;
  1368.       case SIGKILL:
  1369.     sys_siglist[i] = "Killed";
  1370.     break;
  1371.       case SIGBUS:
  1372.     sys_siglist[i] = "Bus Error";
  1373.     break;
  1374.       case SIGSEGV:
  1375.     sys_siglist[i] = "Segmentation fault";
  1376.     break;
  1377.       case SIGSYS:
  1378.     sys_siglist[i] = "Bad Argument to System Call";
  1379.     break;
  1380.       case SIGPIPE:
  1381.     sys_siglist[i] = "Broken Pipe";
  1382.     break;
  1383.       case SIGALRM:
  1384.     sys_siglist[i] = "Alarm Clock";
  1385.     break;
  1386.       case SIGTERM:
  1387.     sys_siglist[i] = "Terminated";
  1388.     break;
  1389. #if    !defined (SIGIO) || SIGUSR1 != SIGIO
  1390.       case SIGUSR1:
  1391.     sys_siglist[i] = "User-defined signal 1";
  1392.     break;
  1393. #endif
  1394. #if    !defined (SIGURG) || SIGUSR2 != SIGURG
  1395.       case SIGUSR2:
  1396.     sys_siglist[i] = "User-defined signal 2";
  1397.     break;
  1398. #endif
  1399. #ifdef    SIGCLD
  1400.       case SIGCLD:
  1401. #endif
  1402. #if    defined(SIGCHLD) && !defined(SIGCLD)
  1403.       case SIGCHLD:
  1404. #endif
  1405.     sys_siglist[i] = "Child Process Exited";
  1406.     break;
  1407. #ifdef    SIGPWR
  1408.       case SIGPWR:
  1409.     sys_siglist[i] = "Power Failure";
  1410.     break;
  1411. #endif
  1412. #ifdef    SIGVTALRM
  1413.       case SIGVTALRM:
  1414.     sys_siglist[i] = "Virtual Timer Alarm";
  1415.     break;
  1416. #endif
  1417. #ifdef    SIGPROF
  1418.       case SIGPROF:
  1419.     sys_siglist[i] = "Profiling Alarm Clock";
  1420.     break;
  1421. #endif
  1422. #ifdef    SIGIO
  1423.       case SIGIO:
  1424.     sys_siglist[i] = "I/O Possible";
  1425.     break;
  1426. #endif
  1427. #ifdef    SIGWINDOW
  1428.       case SIGWINDOW:
  1429.     sys_siglist[i] = "Window System Signal";
  1430.     break;
  1431. #endif
  1432. #ifdef    SIGSTOP
  1433.       case SIGSTOP:
  1434.     sys_siglist[i] = "Stopped (signal)";
  1435.     break;
  1436. #endif
  1437. #ifdef    SIGTSTP
  1438.       case SIGTSTP:
  1439.     sys_siglist[i] = "Stopped";
  1440.     break;
  1441. #endif
  1442. #ifdef    SIGCONT
  1443.       case SIGCONT:
  1444.     sys_siglist[i] = "Continued";
  1445.     break;
  1446. #endif
  1447. #ifdef    SIGTTIN
  1448.       case SIGTTIN:
  1449.     sys_siglist[i] = "Stopped (tty input)";
  1450.     break;
  1451. #endif
  1452. #ifdef    SIGTTOU
  1453.       case SIGTTOU:
  1454.     sys_siglist[i] = "Stopped (tty output)";
  1455.     break;
  1456. #endif
  1457. #ifdef    SIGURG
  1458.       case SIGURG:
  1459.     sys_siglist[i] = "Urgent Condition on Socket";
  1460.     break;
  1461. #endif
  1462. #ifdef    SIGXCPU
  1463.       case SIGXCPU:
  1464.     sys_siglist[i] = "CPU Limit Exceeded";
  1465.     break;
  1466. #endif
  1467. #ifdef    SIGXFSZ
  1468.       case SIGXFSZ:
  1469.     sys_siglist[i] = "File Size Limit Exceeded";
  1470.     break;
  1471. #endif
  1472.       }
  1473. }
  1474. #endif    /* USG and not HAVE_SIGLIST.  */
  1475.  
  1476. #if    defined(USG) && !defined(USGr3) && !defined(HAVE_DUP2)
  1477. int
  1478. dup2 (old, new)
  1479.      int old, new;
  1480. {
  1481.   int fd;
  1482.  
  1483.   (void) close (new);
  1484.   fd = dup (old);
  1485.   if (fd != new)
  1486.     {
  1487.       (void) close (fd);
  1488.       errno = EMFILE;
  1489.       return -1;
  1490.     }
  1491.  
  1492.   return fd;
  1493. }
  1494. #endif    /* USG and not USGr3 and not HAVE_DUP2.  */
  1495.